package MiniC.Parser;

import MiniC.Scanner.Scanner;
import MiniC.Scanner.Token;
import MiniC.Scanner.SourcePos;
import MiniC.Parser.SyntaxError;
import MiniC.ErrorReporter;
import MiniC.AstGen.*;


public class Parser {

    private Scanner scanner;
    private ErrorReporter errorReporter;
    private Token currentToken;
    private SourcePos previousTokenPosition;

    public Parser(Scanner lexer, ErrorReporter reporter) {
	scanner = lexer;
        errorReporter = reporter;
    }

    // accept() checks whether the current token matches tokenExpected.
    // If so, it fetches the next token.
    // If not, it reports a syntax error.
    void accept (int tokenExpected) throws SyntaxError {
	if (currentToken.kind == tokenExpected) {
            previousTokenPosition = currentToken.GetSourcePos();
	    currentToken = scanner.scan();
	} else {
	    syntaxError("\"%\" expected here", Token.spell(tokenExpected));
	}
    }

    // acceptIt() unconditionally accepts the current token
    // and fetches the next token from the scanner.
    void acceptIt() {
        previousTokenPosition = currentToken.GetSourcePos();
	currentToken = scanner.scan();
    }

    // start records the position of the start of a phrase.
    // This is defined to be the position of the first
    // character of the first token of the phrase.
    void start(SourcePos position) {
        position.StartCol = currentToken.GetSourcePos().StartCol;
        position.StartLine = currentToken.GetSourcePos().StartLine;
    }

    // finish records the position of the end of a phrase.
    // This is defined to be the position of the last
    // character of the last token of the phrase.
    void finish(SourcePos position) {
        position.EndCol = previousTokenPosition.EndCol;
        position.EndLine = previousTokenPosition.EndLine;
    }

    void syntaxError(String messageTemplate, String tokenQuoted) throws SyntaxError {
	SourcePos pos = currentToken.GetSourcePos();
	errorReporter.reportError(messageTemplate, tokenQuoted, pos);
	throw(new SyntaxError());
    }

    boolean isTypeSpecifier(int token) {
		if(token == Token.VOID ||
	           token == Token.INT  ||
	           token == Token.BOOL ||
	           token == Token.FLOAT) {
		    return true;
		} else {
		    return false;
		}
    }
    
    boolean isTypeOperator(int token) {
		if(token == Token.PLUS ||
	           token == Token.MINUS  ||
	           token == Token.TIMES ||
	           token == Token.DIV) {
		    return true;
		} else {
		    return false;
		}
    }
    
    boolean isTypeLiteral(int token) {
		if( token == Token.INTLITERAL	|| 
			token == Token.FLOATLITERAL	||
			token == Token.BOOLLITERAL	||
			token == Token.STRINGLITERAL ) {
			return true;
		} else {
			return false;
		}
	}
    
	boolean isTypeCompare(int token) {
		if( token == Token.EQ		||
			token == Token.NOTEQ	||
			token == Token.LESSEQ	||
			token == Token.LESS		||
			token == Token.GREATER	||
			token == Token.GREATEREQ ) {
			return true;
		} else {
			return false;
		}
	}

	boolean isTypeExpr(int token){
    	if( token == Token.PLUS	||
			token == Token.MINUS	||
			token == Token.NOT  ||
			token == Token.ID ||
			isTypeLiteral(token) ||
			token == Token.LEFTPAREN)    		
		{
			return true;
		} else {
			return false;
		}
	}
	
	boolean isTypeStmt(int token){
    	if( token == Token.LEFTBRACE	||
			token == Token.IF	||
			token == Token.WHILE ||
			token == Token.FOR ||			
			token == Token.RETURN ||
			token == Token.ID )    		
		{
			return true;
		} else {
			return false;
		}
	}
	
	
	boolean isTypeLogicOperator(int token){
    	if( token == Token.OR	||
			token == Token.AND	||
			token == Token.NOT)
		{
			return true;
		} else {
			return false;
		}
	}
	
	boolean isType(int token){
	//	if( == Token.)		
		return false;
	}

    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseArrayIndexDecl (Type T):
    //
    // Take [INTLITERAL] and generate an ArrayType
    //
    ///////////////////////////////////////////////////////////////////////////////

    public ArrayType parseArrayIndexDecl(Type T) throws SyntaxError {
	IntLiteral L;
	IntExpr IE;
	accept(Token.LEFTBRACKET);
        SourcePos pos = currentToken.GetSourcePos();
	L = new IntLiteral(currentToken.GetLexeme(), pos);
	accept(Token.INTLITERAL);
	accept(Token.RIGHTBRACKET);
	IE = new IntExpr (L, pos);
	return new ArrayType (T, IE, previousTokenPosition);
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // toplevel parse() routine:
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Program parse() {

        Program ProgramAST = null;

        previousTokenPosition = new SourcePos();
        previousTokenPosition.StartLine = 0;
        previousTokenPosition.StartCol = 0;
        previousTokenPosition.EndLine = 0;
        previousTokenPosition.EndCol = 0;

	currentToken = scanner.scan(); // get first token from scanner...

	try {
            ProgramAST = parseProgram();
	    if (currentToken.kind != Token.EOF) {
		syntaxError("\"%\" not expected after end of program",
			       currentToken.GetLexeme());
	    }
	}
	catch (SyntaxError s) { return null; }
	return ProgramAST;
    }

    
    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseProgram():
    //
    // program ::= ( (VOID|INT|BOOL|FLOAT) ID ( FunPart | VarPart ) )* ";"
    //
    ///////////////////////////////////////////////////////////////////////////////

    // parseProgDecls: recursive helper function to facilitate AST construction.
    public Decl parseProgDecls () throws SyntaxError {
        if (! isTypeSpecifier(currentToken.kind)) {
           return new EmptyDecl (previousTokenPosition);
        }
        SourcePos pos = new SourcePos();
        start(pos);
        Type T = parseTypeSpec();
        ID Ident = parseID();
		if(currentToken.kind == Token.LEFTPAREN) {		//'(' process of function
			   Decl newD = parseFunPart(T, Ident, pos);
	           return new DeclSequence (newD, parseProgDecls(), previousTokenPosition);
		} else {	//except function part
	           DeclSequence Vars = parseVarPart(T, Ident);
	           DeclSequence VarsTail = Vars.GetRightmostDeclSequenceNode();
	           Decl RemainderDecls = parseProgDecls();	//recursive call
	        	VarsTail.SetRightSubtree (RemainderDecls);
	           return Vars;
		}
    }

    public Program parseProgram() throws SyntaxError {
        SourcePos pos = new SourcePos();
        start(pos);
        Decl D = parseProgDecls();
        finish(pos);
        Program P = new Program (D, pos);
        return P;
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseTypeSpec():
    //
    // TypeSpec ::= VOID|INT|BOOL|FLOAT
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Type parseTypeSpec() throws SyntaxError {
        Type T = null;
	switch(currentToken.kind) {
	case Token.INT:
            T = new IntType (currentToken.GetSourcePos());
	    break;
	case Token.BOOL:
            T = new BoolType (currentToken.GetSourcePos());
	    break;
	case Token.FLOAT:
            T = new FloatType (currentToken.GetSourcePos());
	    break;
	case Token.VOID:
            T = new VoidType (currentToken.GetSourcePos());
	    break;
	default:
	    assert(false); // unknown type :(
	}
	acceptIt();
	return T;
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseFunPart():
    //
    // FunPart ::= ( "(" ParamsList? ")" CompoundStmt )
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Decl parseFunPart(Type T, ID Ident, SourcePos pos) throws SyntaxError {

        // We already know that the current token is "(".
        // Otherwise use accept() !
        acceptIt();
	Decl PDecl = parseParamsList(); // can also be empty...
	accept(Token.RIGHTPAREN);
	CompoundStmt CStmt = parseCompoundStmt();
        finish(pos);
	return new FunDecl (T, Ident, PDecl, CStmt, pos);
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseParamsList():
    //
    // ParamsList ::= ParameterDecl ( "," ParameterDecl ) *
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Decl parseParamsList() throws SyntaxError {
        if (!isTypeSpecifier(currentToken.kind)) {
           return new EmptyFormalParamDecl(previousTokenPosition);
        }
        Decl PDecl = parseParameterDecl();
	if (currentToken.kind == Token.COMMA) {
            acceptIt();
        }
        return new FormalParamDeclSequence (PDecl,
                        parseParamsList(), previousTokenPosition);
    } 


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseParameterDecl():
    //
    // ParameterDecl ::= (VOID|INT|BOOL|FLOAT) Declarator
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Decl parseParameterDecl() throws SyntaxError {
        Type T = null;
        Decl D = null;

        SourcePos pos = new SourcePos();
        start(pos);
	if (isTypeSpecifier(currentToken.kind)) {
	    T = parseTypeSpecifier();
	} else {
	    syntaxError("Type specifier instead of % expected",
			Token.spell(currentToken.kind));
	}
	D = parseDeclarator(T, pos);
	return D;
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseDeclarator():
    //
    // Declarator ::= ID ( "[" INTLITERAL "]" )?
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Decl parseDeclarator(Type T, SourcePos pos) throws SyntaxError {
	ID Ident = parseID();
	if (currentToken.kind == Token.LEFTBRACKET) {
	    ArrayType ArrT = parseArrayIndexDecl(T);
            finish(pos);
	    return new FormalParamDecl (ArrT, Ident, pos);
	}
        finish(pos);
	return new FormalParamDecl (T, Ident, pos);
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseVarPart():
    //
    // VarPart ::= ( "[" INTLITERAL "]" )?  ( "=" initializer ) ? ( "," init_decl)* ";"
    //
    ///////////////////////////////////////////////////////////////////////////////

    // process of var Part 
    public DeclSequence parseVarPart(Type T, ID Ident) throws SyntaxError {
    	Type theType = T;
        Decl D;
        DeclSequence Seq = null;
        Expr E = new EmptyExpr(previousTokenPosition);
        if (currentToken.kind == Token.LEFTBRACKET) {
        	theType = parseArrayIndexDecl(T);
        }
        if (currentToken.kind == Token.ASSIGN) {
        	acceptIt();
            // You can use the following code after you have implemented
            // parseInitializer():
	     	E = parseInitializer();
        }
        D = new VarDecl (theType, Ident, E, previousTokenPosition);
        // You can use the following code after implementatin of parseInitDecl():
        
		if (currentToken.kind == Token.COMMA) {
		    acceptIt();
		    Seq = new DeclSequence (D, parseInitDecl(T), previousTokenPosition);
		} else {
	            Seq = new DeclSequence (D, new EmptyDecl (previousTokenPosition),
	                                     previousTokenPosition);
        }
        
	accept (Token.SEMICOLON);
	return Seq;
    }
    
    
    
    /* assignment 2 part
    
    public Expr parseInitializer() throws SyntaxError{
    	if(currentToken.kind == Token.LEFTBRACE){ // '{'
    		acceptIt();
    		parseExpr();
    			while(currentToken.kind == Token.COMMA){
    				acceptIt();
    				parseExpr();    		      	
    	        }
    		accept(Token.RIGHTBRACE);    		
    	}else{
    		parseExpr();
    	}    	 
    }    
    */
    
    public Expr parseInitializer() throws SyntaxError {	
    	// assign operator to init value
		ExprSequence curExprSeq = null;
		ExprSequence preExprSeq = null;
		Expr expr = null;		

		if(currentToken.kind == Token.LEFTBRACE){  // '{' 
			SourcePos pos = new SourcePos( );
			start( pos );
			acceptIt();	// accepts a Token for "{"			
			curExprSeq = new ExprSequence( parseExpr( ), null, pos );
			preExprSeq = curExprSeq; 
			
			while( currentToken.kind == Token.COMMA ) {	// create new tree for right side 			
				acceptIt(); // accepts a Token ","
				expr = parseExpr( );
				curExprSeq.rAST = new ExprSequence( expr, null, previousTokenPosition );
				curExprSeq = ( ExprSequence )curExprSeq.rAST; 
			}
			
			curExprSeq.rAST = new EmptyExpr( currentToken.GetSourcePos( ) );			
			accept( Token.RIGHTBRACE );
			finish( pos );
			return preExprSeq;

		} else {
			return parseExpr( );
		}
	}

    
    /*
       public void parseInit_decl()throws SyntaxError{
    	parseDeclarator();
    	if(currentToken.kind == Token.ASSIGN){
    		acceptIt();
    		parseInitializer();
    	}    	
    
     */
    public DeclSequence parseInitDecl( Type T ) throws SyntaxError {    	
    	DeclSequence dSeq = null;
    	ArrayType arrayType = null;
    	
    	Expr expr = null;
    	VarDecl varDecl = null;
    	//accept(Token.ID);    		
    	SourcePos pos = new SourcePos( );
    	SourcePos pos2 = new SourcePos( );
    	start( pos );
    	start( pos2);
    	ID Ident = parseID( );
    	if(currentToken.kind == Token.LEFTBRACKET){
	    		arrayType = parseArrayIndexDecl(T);
	    		//accept(Token.LEFTBRACKET);
	    		//accept(Token.INTLITERAL);
	    		//accept(Token.RIGHTBRACKET);
	    		if( currentToken.kind == Token.ASSIGN ) {
		    			acceptIt( );	// accept '='
		    			expr = parseInitializer( );
		    			varDecl = new VarDecl( arrayType, Ident, expr, pos );
		    			finish( pos );
		    			if( currentToken.kind == Token.COMMA ) {
							acceptIt( );	// accept for ','
							dSeq = new DeclSequence( varDecl, parseInitDecl( T ), pos2 );
							finish( pos2 );							
		    			}else{    			
		    				dSeq = new DeclSequence( varDecl, new EmptyDecl( previousTokenPosition ), pos );
		    				finish( pos2 );
		    			}
	    		}else{		//no assign init literal in array
		    			dSeq = new DeclSequence( varDecl, new EmptyDecl( previousTokenPosition ), pos );
		    			finish( pos );
		    			
		    			if( currentToken.kind == Token.COMMA ) {
							acceptIt( );	// accept for ','
							dSeq = new DeclSequence( varDecl, parseInitDecl( T ), pos2 );
							finish( pos2 );							
		    			}else{    			
		    				dSeq = new DeclSequence( varDecl, new EmptyDecl( previousTokenPosition ), pos );  
		    				finish( pos2 );
		    			}
	    		}
	    		
    	}else{
	    		if( currentToken.kind == Token.ASSIGN ) {
		    			acceptIt( );	// accept '='    		
		    			expr = parseInitializer( );
		    			varDecl = new VarDecl( T, Ident, expr, pos );
		    			finish(pos);
		    			
		    			if( currentToken.kind == Token.COMMA ) {
							acceptIt( );	// accep for ','
							dSeq = new DeclSequence( varDecl, parseInitDecl( T ), pos2 );
							finish( pos2 );
		    			}else{    			
		    				dSeq = new DeclSequence( varDecl, new EmptyDecl( previousTokenPosition ), pos );
		    				finish( pos2 );
		    			}    		
		    			
	    		}else{		//no assign init literal in variable
	    			varDecl = new VarDecl( T, Ident, new EmptyExpr( previousTokenPosition ), pos );
	    			finish( pos );
	    			
	    			if( currentToken.kind == Token.COMMA ) {
						acceptIt( );	// accept r ','
						dSeq = new DeclSequence( varDecl, parseInitDecl( T ), pos2 );
						finish( pos2 );						
	    			}else{    			
	    				dSeq = new DeclSequence( varDecl, new EmptyDecl( previousTokenPosition ), pos );  
	    				finish( pos2 );	    			
	    			}
	    		}
    	}
    	return dSeq;
    }
    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseUnaryExpr():
    //
    // UnaryExpr ::= ("+"|"-"|"!")* PrimaryExpr
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Expr parseUnaryExpr() throws SyntaxError {
	while (currentToken.kind == Token.PLUS ||
               currentToken.kind == Token.MINUS ||
               currentToken.kind == Token.NOT) {
	    Operator opAST = new Operator (currentToken.GetLexeme(),
					   previousTokenPosition);
	    acceptIt();
	    return new UnaryExpr (opAST, parseUnaryExpr(), previousTokenPosition);
	}
	return parsePrimaryExpr();
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parsePrimaryExpr():
    //
    // PrimaryExpr ::= ID arglist?
    //              |  ID "[" expr "]"
    //              |  "(" expr ")"
    //              |  INTLITERAL | BOOLLITERAL | FLOATLITERAL | STRINGLITERAL
    //
    ///////////////////////////////////////////////////////////////////////////////

    
    
    /* assignment2 part
   public void parsePrimary_expr()throws SyntaxError{
    	
    } 

 */
    public Expr parsePrimaryExpr() throws SyntaxError {		
        // your code goes here...
    	Expr retExpr = null;
		Expr curExpr = null;
		ID Ident;
		// id   or
		SourcePos firstPos = new SourcePos( );
		SourcePos SecondPos = new SourcePos( );
    	switch (currentToken.kind) {
	    	case  Token.ID :
	    		start( firstPos );
	    		start( SecondPos );
	    		//accept(Token.ID);
	    		Ident = parseID(); // accept Token.ID
	    		retExpr = new VarExpr( Ident, firstPos );
				
				
	    		if(currentToken.kind == Token.LEFTPAREN){ //id arglist 	 	    			
	    			curExpr = parseArgList();	
	    			finish( firstPos );
	    			retExpr = new CallExpr( Ident, curExpr, firstPos );    			
	    		}else if(currentToken.kind== Token.LEFTBRACKET){//id [ expr ] 
	    			finish( SecondPos );
	    			accept(Token.LEFTBRACKET);	    			
	    			curExpr = parseExpr();	    			
	    			accept(Token.RIGHTBRACKET);
	    			finish( firstPos );
	    			retExpr = new ArrayExpr( new VarExpr( Ident, SecondPos ), curExpr, firstPos );
	    		}else{	    		
	    			finish( firstPos );
	    		}
	    	break;
	    	case Token.LEFTPAREN :
	    		accept(Token.LEFTPAREN);	    		
	    		retExpr = parseExpr();
	    		accept(Token.RIGHTPAREN);
	    	
	    	break;
	    	case Token.INTLITERAL :
	    		firstPos = currentToken.GetSourcePos( );
	    		IntLiteral intLiteral = new IntLiteral( currentToken.GetLexeme( ), firstPos );
	    		acceptIt();
	    		retExpr = new IntExpr( intLiteral, firstPos );
	    		break;
	    	case Token.BOOLLITERAL :
	    		firstPos = currentToken.GetSourcePos( );
	    		BoolLiteral boolLiteral = new BoolLiteral( currentToken.GetLexeme( ), firstPos );
	    		acceptIt();
	    		retExpr = new BoolExpr( boolLiteral, firstPos );
	    		break;
	    	case Token.FLOATLITERAL:
	    		firstPos = currentToken.GetSourcePos( );
	    		FloatLiteral floatlLiteral = new FloatLiteral( currentToken.GetLexeme( ), firstPos );
	    		acceptIt();
	    		retExpr = new FloatExpr( floatlLiteral, firstPos );
	    		break;
	    	case Token.STRINGLITERAL:
	    		firstPos = currentToken.GetSourcePos( );
	    		StringLiteral stringLiteral = new StringLiteral( currentToken.GetLexeme( ), firstPos );
	    		acceptIt();
	    		retExpr = new StringExpr( stringLiteral, firstPos );
	    		break;
    	default: syntaxError("",
			       currentToken.GetLexeme());    
    	}


		return retExpr;
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseCompoundStmt():
    //
    // CompoundStmt ::= "{" VariableDef* Stmt* "}"
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Decl parseCompoundDecls () throws SyntaxError {
        if (!isTypeSpecifier(currentToken.kind)) {
           return new EmptyDecl (previousTokenPosition);
        }
	        Type T = parseTypeSpec();
	        ID Ident = parseID();
	        DeclSequence Vars = parseVarPart(T, Ident);
	        DeclSequence VarsTail = Vars.GetRightmostDeclSequenceNode();
	        Decl RemainderDecls = parseCompoundDecls();
	        VarsTail.SetRightSubtree (RemainderDecls);
        return Vars;       
    }

    public Stmt parseCompoundStmts () throws SyntaxError {
	if (! (currentToken.kind == Token.LEFTBRACE ||
               currentToken.kind == Token.IF ||
               currentToken.kind == Token.WHILE ||
               currentToken.kind == Token.FOR ||
               currentToken.kind == Token.RETURN ||
               currentToken.kind == Token.ID)
	    ) {
	    return new EmptyStmt(previousTokenPosition);
	}
        Stmt S = null;
        // You can use the following code after implementation of parseStmt():
        S = parseStmt();
        return new StmtSequence (S, parseCompoundStmts(), previousTokenPosition);
    }
    public Stmt parseStmt() throws SyntaxError {
    	Stmt retStmt = null;
    	Stmt stmt = null;
    	Expr expr1 = null;
    	Expr expr2 = null;
    	Expr expr3 = null;
    	ID Ident = null;
    	
	    	switch (currentToken.kind) {
		    	case Token.LEFTBRACE :
		    		retStmt = parseCompoundStmt();
		    		break;
		    	case Token.IF :
		    		retStmt = parseIf_stmt();
		    		break;
		    	case Token.WHILE:
		    		retStmt = parseWhile_stmt();
		    		break;
		    	case Token.FOR :
		    		retStmt = parseFor_stmt();
		    		break;
		    	case Token.RETURN :
		    		retStmt = parseReturnStmt();
		    		break;
		    	case Token.ID :
		    		//accept(Token.ID);
		    		
		    		SourcePos pos = new SourcePos( );
					pos = currentToken.GetSourcePos( );
					Ident = parseID( );
		    		if(currentToken.kind == Token.ASSIGN){
		    			accept(Token.ASSIGN);		    	
							
						expr1 = parseExpr();
						//expr2 = new AssignExpr( new VarExpr( Ident, previousTokenPosition ), expr1, pos );
						retStmt = new AssignStmt(  new VarExpr( Ident, previousTokenPosition ),expr1, pos );
						finish( pos );
						
		    		}else if(currentToken.kind == Token.LEFTBRACKET){ // '['
		    			accept(Token.LEFTBRACKET);
		    			expr1 = parseExpr();
		    			accept(Token.RIGHTBRACKET);
		    			expr2 = new ArrayExpr( new VarExpr( Ident, previousTokenPosition ), expr1, previousTokenPosition );

		    			accept(Token.ASSIGN);
		    			expr3 = parseExpr();
		    			retStmt = new AssignStmt( expr2, expr3, pos );
		    			finish( pos );
		    		}else if(currentToken.kind == Token.LEFTPAREN){ // '('
		    			
		    			expr1= parseArgList( );
		    			Expr callExpr = new CallExpr( Ident, expr1, previousTokenPosition );
		    			retStmt = new CallStmt( callExpr, pos );
		    			finish( pos );		    			
		    		}else{
		    			syntaxError("",
		    				       currentToken.GetLexeme());    
		    		}
		    		accept(Token.SEMICOLON);
		    		break;	    		    	
			default: 
				retStmt = new EmptyStmt( previousTokenPosition );
			
		}   	
	    	
    	return retStmt;
    }
   
	public ReturnStmt parseReturnStmt() throws SyntaxError {

		SourcePos pos = new SourcePos( );
		Expr E = null;
		ReturnStmt RS = null;

		start( pos );
		acceptIt();	// accepts a Token for "RETURN"
		if( currentToken.kind != Token.SEMICOLON ) {
			E = parseExpr();
		}
		else {
			E = new EmptyExpr( previousTokenPosition );
		}
		accept( Token.SEMICOLON );
		RS = new ReturnStmt( E, pos );
		finish( pos );

		return RS;
	}
    
    public IfStmt parseIf_stmt() throws SyntaxError{
    	Expr expr = null;
//    	IfStmt retIfStmt = null;
    	Stmt stmt = null;
    	Stmt stmt2 = null;
    	
    	SourcePos pos = new SourcePos( );
    	start( pos );
    	
    	accept(Token.IF);
    	accept(Token.LEFTPAREN);

    	expr = parseExpr();
    	accept(Token.RIGHTPAREN);
    	
    	stmt = parseStmt();
    	if(currentToken.kind == Token.ELSE){
    		acceptIt();
    		stmt2 = parseStmt();
    		finish( pos );
			return new IfStmt( expr, stmt, stmt2, pos );
    	}    	
    	return new IfStmt( expr, stmt, pos );
    }
    
    public WhileStmt parseWhile_stmt() throws SyntaxError{
    	Expr expr = null;
    	Stmt stmt = null;
    	SourcePos pos = new SourcePos( );
    	start( pos );
    	
    	accept(Token.WHILE);
    	accept(Token.LEFTPAREN);
    	expr = parseExpr();
    	accept(Token.RIGHTPAREN);
    	stmt = parseStmt();
    	finish( pos );
    	return new WhileStmt( expr, stmt, pos );
    }
    
    public ForStmt parseFor_stmt() throws SyntaxError{
    	Expr expr = null;
    	Expr expr2 = null;
    	Expr expr3 = null;
    	Stmt stmt = null;
    	ForStmt forStmt = null;
    	
    	SourcePos pos = new SourcePos( );
    	start( pos );

    	accept(Token.FOR);
    	accept(Token.LEFTPAREN);
    	if(currentToken.kind == Token.ID){
    		expr = parseAsgnexpr();
    	}else {
    		expr = new EmptyExpr( previousTokenPosition );
		}
    	accept(Token.SEMICOLON);
    	
    	if(isTypeExpr(currentToken.kind)){
    		expr2 = parseExpr();
    	}else {
    		expr2 = new EmptyExpr( previousTokenPosition );
		}
    	accept(Token.SEMICOLON);
    	
    	if(currentToken.kind == Token.ID){
    		expr3 = parseAsgnexpr();
    	}else {
    		expr3 = new EmptyExpr( previousTokenPosition );
		}
    	
    	accept(Token.RIGHTPAREN);
    	stmt = parseStmt();
    	finish( pos );
    	forStmt = new ForStmt(expr,expr2,expr3,stmt,pos);
    	return forStmt;
    }
    
    public AssignExpr parseAsgnexpr() throws SyntaxError{
    	SourcePos pos = new SourcePos( );
		AssignExpr assignExpr = null;
		start( pos );
		ID Ident = parseID( );
		Expr expr = new VarExpr( Ident, previousTokenPosition );

    	//accept(Token.ID);
    	accept(Token.ASSIGN);
    	assignExpr = new AssignExpr(expr,parseExpr(),pos);
    	
    	finish( pos );
    	return assignExpr;
    }
    
    public CompoundStmt parseCompoundStmt() throws SyntaxError {
        SourcePos pos = new SourcePos();
        start(pos);
        accept(Token.LEFTBRACE);
        Decl D = parseCompoundDecls();
        Stmt S = parseCompoundStmts();
        accept(Token.RIGHTBRACE);
        finish(pos);
        if ( (D.getClass() == EmptyDecl.class) &&
             (S.getClass() == EmptyStmt.class)) {
           return new EmptyCompoundStmt (previousTokenPosition);
        } else {
        	return new CompoundStmt (D, S, pos);
        }
    }



    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseArgList():
    //
    // ArgList ::= "(" ( arg ( "," arg )* )? ")"
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Expr parseArgs() throws SyntaxError {
	if (currentToken.kind == Token.RIGHTPAREN) {
	    return new  EmptyActualParam (previousTokenPosition);
        } 
		Expr Params = null;
 /*
  * You can use the following code after you have implemented parseExpr() aso.:
  *
  */
        Params = new ActualParam (parseExpr(), previousTokenPosition);
		if (currentToken.kind == Token.COMMA) {
			acceptIt();
	    }

		return new ActualParamSequence (Params, parseArgs(), previousTokenPosition);
    }

    public Expr parseArgList() throws SyntaxError {
		accept(Token.LEFTPAREN); //(
	    Expr Params = parseArgs();
		accept(Token.RIGHTPAREN);
		return Params;
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseID():
    //
    // ID (terminal)
    //
    ///////////////////////////////////////////////////////////////////////////////

    public ID parseID() throws SyntaxError {
		ID Ident = new ID(currentToken.GetLexeme(), currentToken.GetSourcePos());
		accept(Token.ID);
		return Ident;
    }


    ///////////////////////////////////////////////////////////////////////////////
    //
    // parseTypeSpecifier():
    //
    // VOID | INT | FLOAT | BOOL (all terminals)
    //
    ///////////////////////////////////////////////////////////////////////////////

    public Type parseTypeSpecifier() throws SyntaxError {
	Type T = null;
	switch (currentToken.kind) {
	case Token.INT:
	    T = new IntType(currentToken.GetSourcePos());
	    break;
	case Token.FLOAT:
	    T = new FloatType(currentToken.GetSourcePos());
	    break;
	case Token.BOOL:
	    T = new BoolType(currentToken.GetSourcePos());
	    break;
	case Token.VOID:
	    T = new VoidType(currentToken.GetSourcePos());
	    break;
	default:
	    syntaxError("Type specifier expected", "");
	}
	acceptIt();
	return T;
    }
    
    
    ////////////////////////
    //
    // assignment2 code
    //
    /////////////////////////
    
    public void parseInit_decl_list()throws SyntaxError{
    	parseInit_decl();
    	while(currentToken.kind == Token.COMMA){
    		acceptIt();
    		parseInit_decl();    		      	
        }
    }  
    
    
    public void parseInit_decl()throws SyntaxError{
    //	parseDeclarator();	// 
    	if(currentToken.kind == Token.ASSIGN){
    		acceptIt();
    		parseInitializer();
    	}    	
    }
    
    
    
    public Expr parseExpr()throws SyntaxError{
    	if(!isTypeExpr(currentToken.kind)){
    		syntaxError("",
    			       currentToken.GetLexeme());
    	}
    	return parseOr_expr();	//temporary
    }
    
    public Expr parseOr_expr() throws SyntaxError{
    	//and-expr    or    or-expr "||" and-expr
    	Expr curExpr = null;
    	Expr preExpr = null;
		Expr rootExpr = null;
		Operator oper = null;
		//Expr expr = null;
		
    	switch (currentToken.kind) {
	    	case Token.ID :
	    	case Token.LEFTPAREN :
	    	case Token.INTLITERAL :
	    	case Token.BOOLLITERAL :
	    	case Token.FLOATLITERAL:
	    	case Token.STRINGLITERAL:	    		
	    	case Token.PLUS :
	    	case Token.MINUS :
	    	case Token.NOT :
	    		SourcePos pos = new SourcePos( );
	    		start( pos );
	    		curExpr=parseAnd_expr();
	    		rootExpr = curExpr;
	    		preExpr = curExpr;
	    		while(currentToken.kind == Token.OR){
	    			oper = new Operator( currentToken.GetLexeme( ), currentToken.GetSourcePos( ) );	    			
	    			acceptIt(); // or token accept
	    			curExpr = new BinaryExpr( preExpr, oper, parseAnd_expr( ), pos );
	    			//parseAnd_expr();
	    			preExpr = curExpr;
	    		}
	    		finish( pos );
	    		break;	    	
		default: syntaxError("",
			       currentToken.GetLexeme());    
		}   	
    	return curExpr;
    }
    
    public Expr parseAnd_expr() throws SyntaxError{
    	// relational-expr   or       and-expr "&&" relational_expr
    	Expr curExpr = null;
    	Expr preExpr = null;
		Expr rootExpr = null;
		Operator oper = null;
		
    	switch (currentToken.kind) {
	    	case Token.ID :
	    	case Token.LEFTPAREN :
	    	case Token.INTLITERAL :
	    	case Token.BOOLLITERAL :
	    	case Token.FLOATLITERAL:
	    	case Token.STRINGLITERAL:	    		
	    	case Token.PLUS :
	    	case Token.MINUS :
	    	case Token.NOT :
	    		SourcePos pos = new SourcePos( );
	    		start( pos );
	    		curExpr = parseRelational_expr();
	    		rootExpr = curExpr;
	    		preExpr = curExpr;
	    		while(currentToken.kind == Token.AND){
	    			oper = new Operator( currentToken.GetLexeme( ), currentToken.GetSourcePos( ) );	    	
	    			acceptIt();
	    			curExpr = new BinaryExpr( preExpr, oper, parseRelational_expr(), pos );
	    			preExpr = curExpr;
	    		}
	    		break;	    	
		default: syntaxError("",
			       currentToken.GetLexeme());    
		}   	
    	return curExpr;
    }
    
    public Expr parseRelational_expr()throws SyntaxError{
    	// add_expr   or   6type
    	Expr curExpr = null;
    	Expr preExpr = null;
		Expr rootExpr = null;
		Operator oper = null;
		
    	switch (currentToken.kind) {
	    	case Token.ID :
	    	case Token.LEFTPAREN :
	    	case Token.INTLITERAL :
	    	case Token.BOOLLITERAL :
	    	case Token.FLOATLITERAL:
	    	case Token.STRINGLITERAL:	    		
	    	case Token.PLUS :
	    	case Token.MINUS :
	    	case Token.NOT :
	    		SourcePos pos = new SourcePos( );
	    		start( pos );
	    		curExpr= parseAdd_expr();
	    		rootExpr = curExpr;
	    		preExpr = curExpr;
	    		
	    		while(isTypeCompare(currentToken.kind)){
	    			oper = new Operator( currentToken.GetLexeme( ), currentToken.GetSourcePos( ) );	    
	    			acceptIt();
	    			curExpr = new BinaryExpr( preExpr, oper, parseAdd_expr(), pos );
	    			preExpr = curExpr;
	    		}
	    		break;	    	
		default: syntaxError("",
			       currentToken.GetLexeme());    
		}   	
    	
    	return curExpr;
    }
    
    public Expr parseAdd_expr()throws SyntaxError{
    	// parseMulti_expr   or   2type
    	Expr curExpr = null;
    	Expr preExpr = null;
		Expr rootExpr = null;
		Operator oper = null;
		
    	switch (currentToken.kind) {
	    	case Token.ID :
	    	case Token.LEFTPAREN :
	    	case Token.INTLITERAL :
	    	case Token.BOOLLITERAL :
	    	case Token.FLOATLITERAL:
	    	case Token.STRINGLITERAL:	    		
	    	case Token.PLUS :
	    	case Token.MINUS :
	    	case Token.NOT :
	    		SourcePos pos = new SourcePos( );
	    		start( pos );
	    		curExpr = parseMult_expr();
	    		rootExpr = curExpr;
	    		preExpr = curExpr;
	    		while((currentToken.kind == Token.PLUS) || (currentToken.kind == Token.MINUS)){
	    			oper = new Operator( currentToken.GetLexeme( ), currentToken.GetSourcePos( ) );	
	    			acceptIt();
	    			curExpr = new BinaryExpr( preExpr, oper, parseMult_expr(), pos );
	    			preExpr = curExpr;
	    		}
	    		break;	    	
		default: syntaxError("",
			       currentToken.GetLexeme());    
		}   	
    	return curExpr;
    }
    
    public Expr parseMult_expr()throws SyntaxError{
    	// unary_expr   or   
    	Expr curExpr = null;
    	Expr preExpr = null;
		Expr rootExpr = null;
		Operator oper = null;
	   	switch (currentToken.kind) {
	    	case Token.ID :
	    	case Token.LEFTPAREN :
	    	case Token.INTLITERAL :
	    	case Token.BOOLLITERAL :
	    	case Token.FLOATLITERAL:
	    	case Token.STRINGLITERAL:	    		
	    	case Token.PLUS :
	    	case Token.MINUS :
	    	case Token.NOT :
	    		SourcePos pos = new SourcePos( );
	    		start( pos );
	    		curExpr= parseUnary_expr();
	    		rootExpr = curExpr;
	    		preExpr = curExpr;
	    		while((currentToken.kind == Token.TIMES) || (currentToken.kind == Token.DIV)){
	    			oper = new Operator( currentToken.GetLexeme( ), currentToken.GetSourcePos( ) );	
	    			acceptIt();	    			
	    			curExpr = new BinaryExpr( preExpr, oper, parseUnaryExpr(), pos );
	    			preExpr = curExpr;
	    		}
	    		break;	    	
		default: syntaxError("",
			       currentToken.GetLexeme());    
		}   	
	   	return curExpr;
    }
    
    public Expr parseUnary_expr()throws SyntaxError{
    	// primary_expr   or
    	Expr curExpr = null;
    	Expr preExpr = null;
		Expr rootExpr = null;
		Operator oper = null;
	   	switch (currentToken.kind) {
	    	case Token.ID :
	    	case Token.LEFTPAREN :
	    	case Token.INTLITERAL :
	    	case Token.BOOLLITERAL :
	    	case Token.FLOATLITERAL:
	    	case Token.STRINGLITERAL:
	    		return parsePrimaryExpr();	    		
	    	case Token.PLUS :
	    	case Token.MINUS :
	    	case Token.NOT :
	    		oper = new Operator ( currentToken.GetLexeme(), previousTokenPosition );
	    		acceptIt();
	    		return new UnaryExpr(oper,parseUnary_expr(),previousTokenPosition);   			    	
		default: syntaxError("",
			       currentToken.GetLexeme());    
		}
	   	return parsePrimaryExpr();
    }
  
    // already exist
    /*
    public void parseArgList()throws SyntaxError{
       	accept(Token.LEFTPAREN);
       	if(isTypeExpr(currentToken.kind)){
       		parseArgs();
       	}
    	accept(Token.RIGHTPAREN);
    }
    
    public void parseArgs()throws SyntaxError{
       	parseArg();
       	while(currentToken.kind == Token.COMMA){
			accept(Token.COMMA);
			parseArgs();			
		}
    }
    */
    
    public void parseArg()throws SyntaxError{    	
    	parseExpr();    	
    }
    
    
    
    
    

}
